package com.gitee.huanminabc.jlambda_sql.jdbc;

import com.gitee.huanminabc.jcommon.base.SnowIdUtil;
import com.gitee.huanminabc.jcommon.exception.CommonException;
import lombok.extern.slf4j.Slf4j;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.*;
import java.util.function.Supplier;

/**
 * @description:
 * @author: huanmin
 * @create: 2025-04-10 10:09
 **/
@Slf4j
public class TransactionManage {

    //事物管理器
    protected static final ThreadLocal<Map<String,Connection>> transactionConnectionManage = new ThreadLocal<>();
    protected static final ThreadLocal<Deque<String>> transactionKey = new ThreadLocal<>();

    //入站
    protected static void  pushTransactionKey(String transactionKey) {
        Deque<String> transactionKeys = TransactionManage.transactionKey.get();
        if (transactionKeys == null) {
            transactionKeys = new ArrayDeque<>();
            TransactionManage.transactionKey.set(transactionKeys);
        }
        transactionKeys.push(transactionKey);
    }
    //出站
    protected static String popTransactionKey() {
        Deque<String> transactionKeys = TransactionManage.transactionKey.get();
        if (transactionKeys == null) {
            return null;
        }
        return transactionKeys.poll();
    }
    //获取值但是不删除
    protected static String peekTransactionKey() {
        Deque<String> transactionKeys = TransactionManage.transactionKey.get();
        if (transactionKeys == null) {
            return null;
        }
        return transactionKeys.peek();
    }

    //判断当前是否有事务
    public static boolean isTransaction() {
        return transactionConnectionManage.get()!= null&& !transactionConnectionManage.get().isEmpty();
    }
    //关闭当前事务
    public static void closeTransaction(String transactionKey) {
        Map<String, Connection> connectionMap = transactionConnectionManage.get();
        if (connectionMap != null) {
            Connection connection = connectionMap.get(transactionKey);
            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException e) {
                    throw new CommonException(e, "Error closing transaction connection");
                }
            }
            connectionMap.remove(transactionKey);
        }
    }

    //获取当前事务的连接
    public static Connection getTransactionConnection(String transactionKey) {
        Map<String, Connection> connectionMap = transactionConnectionManage.get();
        if (connectionMap == null) {
            connectionMap = new HashMap<>();
            transactionConnectionManage.set(connectionMap);
        }
        //如果没有开启事物就创建一个新的连接

        return connectionMap.get(transactionKey);
    }
    //添加当前事务的连接
    public static void addTransactionConnection(String transactionKey, Connection connection) {
        //入站
        pushTransactionKey(transactionKey);
        Map<String, Connection> connectionMap = transactionConnectionManage.get();
        if (connectionMap == null) {
            connectionMap = new HashMap<>();
            transactionConnectionManage.set(connectionMap);
        }
        connectionMap.put(transactionKey, connection);
    }

    //事务处理
    public static <R>  R  transaction(Supplier<R> supplier) throws SQLException {
        Connection connection = JdbcCommand.getNewConnection();
        String transactionKey = SnowIdUtil.uniqueLongHex();
        TransactionManage.addTransactionConnection(transactionKey, connection);
        try {
            connection.setAutoCommit(false);
            //执行业务逻辑
            R apply = supplier.get();
            //提交事物
            commitTransaction();
            return apply;
        } catch (Exception e) {
            //回滚事物
            rollbackTransaction();
            throw e;
        }
    }

    //手动开启事物
    public static void openTransaction(String transactionKey) {
        //如果不想将事务加入当前线程父事务中,那么新建一个新的连接
        if (!Objects.equals(JdbcManage.getDbKey(), transactionKey)) {
            Connection newConnection = JdbcCommand.getNewConnection();
            TransactionManage.addTransactionConnection(transactionKey, newConnection);
        }
        //如果当前没有开启事物,那么就创建一个新的连接 (第一次的时候)
        Connection connection = TransactionManage.getTransactionConnection(transactionKey);
        if (connection == null) {
            connection = JdbcCommand.getNewConnection();
            TransactionManage.addTransactionConnection(transactionKey, connection);
        }
        try {
            connection.setAutoCommit(false);
        } catch (SQLException e) {
            throw new CommonException(e, "Error opening transaction");
        }
    }

    //默认开启的事物, 用的transactionKey=JdbcManage.getDbKey() , 只有子事物并且不加入到父事务的才会使用自己的key
    public static void openTransaction() {
        String dbKey = JdbcManage.getDbKey();
        if (dbKey== null) {
            throw new CommonException("No data source key set");
        }
        openTransaction(dbKey);
    }

    //手动提交事物
    public static void commitTransaction() {
        String transactionKey = popTransactionKey();
        Connection connection = TransactionManage.getTransactionConnection(transactionKey);
        if (connection == null) {
            throw new CommonException("No transaction connection found");
        }
        try {
            connection.commit();
        } catch (SQLException e) {
            throw new CommonException(e, "Error committing transaction");
        }finally {
            closeTransaction(transactionKey);
        }
    }

    //手动回滚事物
    public static void rollbackTransaction() {
        String transactionKey = popTransactionKey();
        Connection connection = TransactionManage.getTransactionConnection(transactionKey);
        if (connection == null) {
            throw new CommonException("No transaction connection found");
        }
        try {
            connection.rollback();
        } catch (SQLException e) {
            throw new CommonException(e, "Error rolling back transaction");
        }finally {
            try {
                connection.close();
                TransactionManage.transactionConnectionManage.remove();
            } catch (SQLException e) {
                log.error("Error rolling back transaction", e);
            }
        }
    }
}
